//*******************************************************************       //
//IMPORTANT NOTICE                                                          //
//================                                                          //
//Copyright Mentor Graphics Corporation 1996 - 1999.  All rights reserved.  //
//This file and associated deliverables are the trade secrets,              //
//confidential information and copyrighted works of Mentor Graphics         //
//Corporation and its licensors and are subject to your license agreement   //
//with Mentor Graphics Corporation.                                         //
//                                                                          //
//Use of these deliverables for the purpose of making silicon from an IC    //
//design is limited to the terms and conditions of your license agreement   //
//with Mentor Graphics If you have further questions please contact Mentor  //
//Graphics Customer Support.                                                //
//                                                                          //
//This Mentor Graphics core (m8051w v2002.080) was extracted on             //
//workstation hostid 8316cbec Inventra                                      //
// M8051W/EW Test Bench 
// 
// $Log: m8051w_tb.v,v $
// Revision 1.1  2002/01/09
// Final testbench changes for version2
//
// Revision 1.1  2001/11/14
// First EW checkin
//
// Revision 1.2  2000/03/06
// Revised configuration scheme
//
// Revision 1.1  2000/02/05
// Name change from m8051e to m8051ewarp
//
// Revision 1.1.1.1  1999/10/28
// "initialization and source check-in for m8051e"
//
//
////////////////////////////////////////////////////////////////////////////////
//
// Purpose      :       M8051W/EW Soft Core Test Bench
//
////////////////////////////////////////////////////////////////////////////////

`include "m8051w_tb_cfg.v"
`define ID1_SEG 		m8051w_tb.uRAP.uESFR.CAN_ESFR.i_can_bsp.rx_id1 
`define CAN1_TX_ECT 	m8051w_tb.uRAP.uESFR.CAN_ESFR.i_can_registers.tx_err_cnt
`define CAN1_RX_ECT 	m8051w_tb.uRAP.uESFR.CAN_ESFR.i_can_registers.rx_err_cnt
`define CAN2_TX_ECT 	m8051w_tb.uRAP.uESFR.CAN2_ESFR.i_can_registers.tx_err_cnt
`define CAN2_RX_ECT 	m8051w_tb.uRAP.uESFR.CAN2_ESFR.i_can_registers.rx_err_cnt
`define TX_POINT    	m8051w_tb.uRAP.uESFR.CAN_ESFR.i_can_bsp.tx_point
`define SAMPLE_POINT    m8051w_tb.uRAP.uESFR.CAN_ESFR.i_can_bsp.sample_point
`define TX_BUFF_STATUS 	m8051w_tb.uRAP.uESFR.CAN_ESFR.i_can_registers.transmit_buffer_status
`define RX_AND_TX 		m8051w_tb.rx_and_tx
`define ACK_LIM	 		m8051w_tb.uRAP.uESFR.CAN_ESFR.i_can_bsp.rx_ack_lim
`define EOF				m8051w_tb.uRAP.uESFR.CAN_ESFR.i_can_bsp.rx_eof
`define INTER 			m8051w_tb.uRAP.uESFR.CAN_ESFR.i_can_bsp.rx_inter	


module m8051w_tb();  
//*******************************************************************       //
//IMPORTANT NOTICE                                                          //
//================                                                          //
//Copyright Mentor Graphics Corporation 1996 - 1999.  All rights reserved.  //
//This file and associated deliverables are the trade secrets,              //
//confidential information and copyrighted works of Mentor Graphics         //
//Corporation and its licensors and are subject to your license agreement   //
//with Mentor Graphics Corporation.                                         //
//                                                                          //
//Use of these deliverables for the purpose of making silicon from an IC    //
//design is limited to the terms and conditions of your license agreement   //
//with Mentor Graphics If you have further questions please contact Mentor  //
//Graphics Customer Support.                                                //
//                                                                          //
//This Mentor Graphics core (m8051w v2002.080) was extracted on             //
//workstation hostid 8316cbec Inventra                                      //
               
  tri1 [7:0] PORT0;
  tri  [7:0] PORT1, PORT2, PORT3;

  reg           XTAL1, RST, TRESET;
 	 

m8051w_top uRAP (.PORT0(PORT0), .PORT1(PORT1), .PORT2(PORT2),
                      .PORT3(PORT3), .XTAL2(XTAL2), .NPSEN(NPSEN),
                      .XTAL1(XTAL1), .RST(RST), .TRESET(TRESET));

i2c_slave_model #(7'b0010_000) i2c_slave 
(	.scl(PORT2[6]),
	.sda(PORT2[7])
);

spi_slave spi_slave_module_1
(	.sysclk(XTAL1),
	.reset(RST),
	.SPI_CLK(PORT2[0]),
	.SPI_MISO(PORT2[2]),
	.SPI_MOSI(PORT2[1]),
	.SPI_SS(PORT3[4])
);

spi_slave spi_slave_module_2
(	.sysclk(XTAL1),
	.reset(RST),
	.SPI_CLK(PORT2[3]),
	.SPI_MISO(PORT2[5]),
	.SPI_MOSI(PORT2[4]),
	.SPI_SS(PORT3[5])
);

//build can
wire	tx_tmp1;
wire	tx_tmp2;
wire	rx_and_tx;
wire	tx;
reg		delayed_tx;

assign	tx_tmp1 = PORT1[3];
assign	tx_tmp2 = PORT1[5];
assign	tx = tx_tmp1 & tx_tmp2;

// Generating delayed tx signal (CAN transciever delay)
always
begin
  wait (tx);
  repeat (16) @ (posedge XTAL1);   // 4 time quants delay
  #1 delayed_tx = tx;
  wait (~tx);
  repeat (16) @ (posedge XTAL1);   // 4 time quants delay
  #1 delayed_tx = tx;
end

assign rx_and_tx = (delayed_tx);
assign PORT1[4] = rx_and_tx;
assign PORT1[2] = rx_and_tx;

assign PORT3[0] = PORT3[1];

/* Clock oscillator process */
initial
begin
   XTAL1 = 1'b0;
   forever
           #`Thclk XTAL1 = !XTAL1;
end



/* Reset process */
initial
begin
  // Test reset
  RST    = 1'b0;
  TRESET = 1'b1;
  #`Ttres TRESET = 1'b0;

  // Run
  #`Tclk;
  #`Tclk;
  #`Tclk;
  #`Tclk;

  // Compatible reset
  RST    = 1'b1;
  #`Tres  RST    = 1'b0;

  // Run
  #`Tmaxrun;
  $display("Error:       At time %t, simulation time exhausted", $time);
  display_test_info; 
  $finish;
end

/* CAN_ERROR_TEST  */
  integer bit_counter;
  integer test_cnt;
  event lsy;
  event haha;

  reg [7:0] can1_tx_err_cnt;
  reg [7:0] can1_rx_err_cnt;
  reg [7:0] can2_tx_err_cnt;
  reg [7:0] can2_rx_err_cnt;
  
  reg		can1_error_irq_ok;
  reg 		can_error_cnt_ok;
  reg		can_busoff_ok;
  reg		can_recover_bus_off_ok;
  reg		can_error_rule_9_ok;
  reg		can_error_rule_11_ok;
  reg		can_overload_frame_ok;

  reg  id1_delay;
  wire id1_start;


  always
     id1_delay = #5 `ID1_SEG;
	
  assign id1_start = `ID1_SEG & ~id1_delay;

  initial
  begin
	wait(PORT0 == "@");
	can1_tx_err_cnt = 0; 
    can1_rx_err_cnt = 0;
    can2_tx_err_cnt = 0;
    can2_rx_err_cnt = 0;
	//send 1 basic frame, total bit length is 52 bits
	for(test_cnt = 1;test_cnt<=48;test_cnt=test_cnt+1)
	begin
      if(   test_cnt != 23 && test_cnt != 24 && test_cnt != 25 && 
	        test_cnt != 26 && test_cnt != 27 && test_cnt != 28 &&
			test_cnt != 29 && test_cnt != 30 && test_cnt != 31 )	
	  //at 23th to 31th, make no error, transmit and receive success, rx&tx cnt -1
	  begin
	    ->lsy;
        bit_counter = 0;

	    wait(id1_start);	//can 1 in id1
	    while(bit_counter < test_cnt)
	    begin		//inverte bit 3
	      @(posedge `TX_POINT);
	        bit_counter = bit_counter + 1;
	    end
	    repeat (40) @( posedge m8051w_tb.XTAL1);	//delay same time to tb's delayed_tx signal
	  //when in id1 region
	    if(`ID1_SEG && m8051w_tb.rx_and_tx == 1)  //rule3.exc2 
	    begin
		  can1_tx_err_cnt = can1_tx_err_cnt;
		  can1_rx_err_cnt = can1_rx_err_cnt + 1;
		  can2_rx_err_cnt = can2_rx_err_cnt + 1;
	    end
		else if(`ACK_LIM || `EOF)		//when ack_lim, meet ack can2 rx -1, and ack_lim wrong, +1
		  if(can1_tx_err_cnt == 255)
		  begin
		    can1_tx_err_cnt = 128;
			can1_rx_err_cnt = 0;
	      end
		  else
		    can1_tx_err_cnt = can1_tx_err_cnt + 8;
	    else					//send 0, forces to 0, bit error
	    begin
	      if(can1_tx_err_cnt == 255)
	        begin
	        can1_tx_err_cnt = 128;		//bus node off
	        can1_rx_err_cnt = 0;
	        end
	      else
	        can1_tx_err_cnt = can1_tx_err_cnt + 8;
	      can2_rx_err_cnt = can2_rx_err_cnt + 1;
	    end
	    
	    force m8051w_tb.rx_and_tx = ~m8051w_tb.rx_and_tx;		// bit inverte
   	    @(posedge `TX_POINT); 
	    release m8051w_tb.rx_and_tx;

	    if(test_cnt == 21) //this loop make can become passive node, should send active error flag
	    begin
	      can_error_rule_9_ok = 1;
	      repeat(6)
	      begin
	        @(posedge `TX_POINT);
	        if(`RX_AND_TX != 0)
	          can_error_rule_9_ok = 0;
	      end
	    end
	    if(test_cnt == 22)	//tx_cnt = 136, send passive error flag
	    begin
	      repeat(6)
	      begin
	        @(posedge `TX_POINT);
	        if(`RX_AND_TX != 1)
	          can_error_rule_9_ok = 0;
	      end
	    end
	    if(test_cnt == 32)	//tx_cnt = 128, send active error flag
	    begin
	      can_error_rule_11_ok = 1;
	      repeat(6)
	      begin
	        @(posedge `TX_POINT);
	        if(`RX_AND_TX != 0)
	          can_error_rule_11_ok = 0;
	      end
	    end
	  end

	//at 23th to 31th, make no error, transmit and receive success, rx&tx cnt -1
	  else if(test_cnt == 23 || test_cnt == 24 || test_cnt == 25 || 
	          test_cnt == 26 || test_cnt == 27 || test_cnt == 28 ||
		   	  test_cnt == 29 || test_cnt == 30 || test_cnt == 31 )	
	  begin
	    ->haha;
	    wait(`TX_BUFF_STATUS);
	    can1_tx_err_cnt = can1_tx_err_cnt -1;
	    can2_rx_err_cnt = can2_rx_err_cnt -1;
		repeat(3) @(posedge `SAMPLE_POINT);
	  end
    end
   
    repeat(15) @(posedge `TX_POINT);//check if error cnt is right.
	if((can1_tx_err_cnt == `CAN1_TX_ECT) && (can1_rx_err_cnt == `CAN1_RX_ECT) &&
	   (can2_tx_err_cnt == `CAN2_TX_ECT) && (can2_rx_err_cnt == `CAN2_RX_ECT)
	   )
	begin
	  can_error_cnt_ok = 1; 
	end
	else
	begin
	  can_error_cnt_ok = 0;
	end
	if(uRAP.uESFR.CAN_ESFR.bus_off_on == 0)
	begin
	  can_busoff_ok = 1;	
	end
	else
	begin
	  can_busoff_ok = 0;
	end

	/* rule 4 rule 5 rule 6 rule 2 check */
    //not implement yet and not plan to implement :) //


	force PORT0 = "Q";	//let software exit the reset mode 
	repeat(2) @(posedge `SAMPLE_POINT);
	release PORT0;
	//recovery of bus node off	
	repeat(1450) @(posedge `SAMPLE_POINT);

	if(uRAP.uESFR.CAN_ESFR.bus_off_on == 1 && `CAN1_TX_ECT == 0 && 
	   `CAN1_RX_ECT == 0)
	  can_recover_bus_off_ok = 1;
	else
	  can_recover_bus_off_ok = 0;

	// overload frame test //
	/* invert inter frame's 1st and 2nd bit */
	can_overload_frame_ok = 1;
	wait(`INTER);
	->lsy;
	@(posedge `TX_POINT);		//first inter bit
	force `RX_AND_TX = ~`RX_AND_TX;
	@(posedge `TX_POINT);
	release `RX_AND_TX;
	
	repeat(6)
	begin
 	  @(posedge `SAMPLE_POINT);
	  if(`RX_AND_TX != 0)
	    can_overload_frame_ok = 0;
	end
	
	repeat (7) @(posedge `SAMPLE_POINT);	//inveter at 8th on overload lim
	@(posedge `TX_POINT);
	->haha;
	force `RX_AND_TX = ~`RX_AND_TX;
	@(posedge `TX_POINT);
	release `RX_AND_TX;

	repeat(6)
	begin
 	  @(posedge `SAMPLE_POINT);
	  if(`RX_AND_TX != 0)
	    can_overload_frame_ok = 0;
	end
	if((can1_tx_err_cnt == `CAN1_TX_ECT) && (can1_rx_err_cnt == `CAN1_RX_ECT) &&
	   (can2_tx_err_cnt == `CAN2_TX_ECT) && (can2_rx_err_cnt == `CAN2_RX_ECT)
	   )
	  can_overload_frame_ok = 0;
	

	wait(`INTER);
	->lsy;
	@(posedge `TX_POINT);	//second inter bit	//this inter begin from tx_point
	force `RX_AND_TX = ~`RX_AND_TX;
	@(posedge `TX_POINT);
	release `RX_AND_TX;
	
	repeat(6) 		//send 6 0, overload flag
	begin
	  @(posedge `SAMPLE_POINT);
	  if(`RX_AND_TX != 0)
	    can_overload_frame_ok = 0;
	end



	#10000000;

	force PORT0 = "w";	//set P0 = w, let software out of error test function.
	repeat (10) @(posedge `TX_POINT);
	release PORT0;
  end

  initial  //test if can trigger a error interrupt
  begin
   wait(can1_tx_err_cnt==96);
  	repeat (2) @(posedge `SAMPLE_POINT);
	if(PORT0 == "q")
	   can1_error_irq_ok = 1;
	else
	   can1_error_irq_ok = 0;
  end




// Program bus monitor for crash detection
always @(posedge uRAP.SCLK) begin
  if (^uRAP.PROGA === 1'bx && ~uRAP.TRESET) begin
    $display("Bus Error:   At time %t, program address indeterminate: %b",
             $time, uRAP.PROGA);
    $finish;
  end
  if(PORT0 === "$") begin
    $display("Information: At time %t, program test over",$time);
	display_test_info;	
	$finish;
  end
//  else if (PROGA == `EXIT_ADDRESS) begin
//    $display("Information: At time %t, program address reached exit loop",
//             $time);
//    #(`Thclk * 2.0);
//    $finish;
//  end
end

task display_test_info;
integer file_ptr;
reg [15:0] mem_ptr;
reg [7:0] temp_char;

begin
// file variables

    file_ptr = $fopen("test_result","a");
    mem_ptr = 16'h2000;
	$fdisplay(file_ptr,"\n--------------------------test result--------------------------\n");
	while(uRAP.uXRAM.MEM[mem_ptr] != "$")
	begin
	   	$fwrite(file_ptr,"%c",uRAP.uXRAM.MEM[mem_ptr]);
		mem_ptr=mem_ptr+1;
	end
	//write can error test information
	if(can1_error_irq_ok === 1)
	   $fdisplay(file_ptr,"OK_can basic_error irq");
	else if(can1_error_irq_ok === 0)
	   $fdisplay(file_ptr,"FAIL_can basic_error irq");
	if(can_error_cnt_ok === 1)
	   $fdisplay(file_ptr,"OK_can basic_error cnt");
	else if (can_error_cnt_ok === 0)
	   $fdisplay(file_ptr,"FAIL_can basic_error cnt");
	if(can_busoff_ok === 1)
	   $fdisplay(file_ptr,"OK_can basic_bus off mode");
	else if (can_busoff_ok === 0)
	   $fdisplay(file_ptr,"FAIL_can basic_bus off mode");
	if(can_recover_bus_off_ok === 1)
	   $fdisplay(file_ptr,"OK_can basic_recover bus off");
	else if (can_recover_bus_off_ok === 0)
	   $fdisplay(file_ptr,"FAIL_can basic_recover bus off");
	if(can_error_rule_9_ok === 1)
	   $fdisplay(file_ptr,"OK_can basic_error rule 9");
	else if (can_error_rule_9_ok === 0)
	   $fdisplay(file_ptr,"FAIL_can basic_error rule 9");
	if(can_error_rule_11_ok === 1)
	   $fdisplay(file_ptr,"OK_can basic_error rule 11");
	else if (can_error_rule_11_ok === 0)
	   $fdisplay(file_ptr,"FAIL_can basic_error rule 11");
	if(can_overload_frame_ok === 1)
	   $fdisplay(file_ptr,"OK_can basic_overload frame");
	else if (can_overload_frame_ok === 0)
	   $fdisplay(file_ptr,"FAIL_can basic_overload frame");

	

	$fdisplay(file_ptr,"\n---------------------test result finish-------------------------\n");
    $fclose(file_ptr);
end
endtask
endmodule
